package it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyScrollPanel;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseListener;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseListenerHandler;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyPNGImage.FPNGImage;


public class VBar extends VerticalPanel {
    int arrowWidth = 20;
    int arrowHeight = 20;
    FPNGImage upArrow;
    FPNGImage downArrow;
    AbsolutePanel central;
    Cursor cursor;
    boolean moveIt = false;
    int childHeight;
    int realCursorHeight;
    boolean hasFixedHeight = false;


    private FScrollListenerCollection scrollListenerCollection;

    public VBar() {


        cursor = new Cursor();
        cursor.setPixelSize(arrowWidth, 50);
        cursor.setStyleName("fuzzy-vBarCursor");

        central = new AbsolutePanel() {

            public void onBrowserEvent(Event event) {

                if (DOM.isOrHasChild(this.getElement(), DOM.eventGetTarget(event))) {
                    DOM.eventPreventDefault(event);
                }
            }
        };
        central.sinkEvents(Event.ONMOUSEDOWN);
        central.setStyleName("fuzzy-vBarCentral");
        central.add(cursor);

        upArrow = new FPNGImage();
        downArrow = new FPNGImage();

        add(upArrow);
        add(central);
        add(downArrow);

        setStyleName("fuzzy-vBar");

        addCursorMoveListener();
        addArrowsMouseListeners();


        scrollListenerCollection = new FScrollListenerCollection();

    }

    private void addCursorMoveListener() {


        cursor.addMouseListener(new MouseListener() {
            int dragStartX
                    ,
                    dragStartY
                    ,
                    widgetTop;

            public void onMouseDown(Widget widget, int i, int i1) {
                moveIt = true;
                DOM.setCapture(widget.getElement());
                dragStartX = i;
                dragStartY = i1;
            }

            public void onMouseEnter(Widget widget) {
            }

            public void onMouseLeave(Widget widget) {
            }

            public void onMouseMove(Widget widget, int i, int i1) {

                widgetTop = central.getWidgetTop(cursor);

                int top = i1 + widgetTop;

                if (moveIt) {

                    if (!hasFixedHeight) {
                        if ((top - dragStartY) >= 0 && ((top - dragStartY) + realCursorHeight) <= (central.getOffsetHeight())) {
                            central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), top - dragStartY);
                            scrollListenerCollection.fireOnScroll(calculateDispacement());
                        } else if ((top - dragStartY) < 0) {
                            central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), 0);
                            scrollListenerCollection.fireOnScroll(0);
                        } else if (((top - dragStartY) + realCursorHeight) > (central.getOffsetHeight())) {
                            central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), (central.getOffsetHeight() - realCursorHeight));
                            scrollListenerCollection.fireOnScroll(calculateDispacement());
                        }
                    } else {

                    }
                }
            }

            public void onMouseUp(Widget widget, int i, int i1) {
                moveIt = false;
                DOM.releaseCapture(widget.getElement());

            }
        });

    }

    private void addArrowsMouseListeners() {
        final Timer upArrowTimer = new Timer() {

            public void run() {

                int pos = central.getWidgetTop(cursor) - central.getOffsetHeight() / 100;

                if (pos <= 0) {
                    central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), 0);
                    scrollListenerCollection.fireOnScroll(0);
                } else {
                    central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), pos);
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                }


            }
        };
        final Timer downArrowTimer = new Timer() {

            public void run() {
                int pos = central.getWidgetTop(cursor) + central.getOffsetHeight() / 100;

                if ((pos + realCursorHeight) > (central.getOffsetHeight())) {
                    central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), (central.getOffsetHeight() - realCursorHeight));
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                } else {
                    central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), pos);
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                }


            }
        };
        FMouseListener.setMouseEvent(upArrow.getElement(), new FMouseListenerHandler() {

            public void onClick() {

            }

            public void onMouseDown(int i, int i1) {
                upArrowTimer.run();
                upArrowTimer.scheduleRepeating(20);
            }

            public void onMouseEnter() {

                upArrowTimer.run();
                upArrowTimer.scheduleRepeating(20);
            }

            public void onMouseLeave() {
                upArrowTimer.cancel();
            }

            public void onMouseUp(int i, int i1) {
                upArrowTimer.cancel();
            }

            public void onMouseWheelUp(int intensity) {

            }

            public void onMouseWheelDown(int intensity) {

            }

            public void onMouseMove(int x, int y) {

            }
        });
        FMouseListener.setMouseEvent(downArrow.getElement(), new FMouseListenerHandler() {

            public void onClick() {

            }

            public void onMouseDown(int i, int i1) {
                downArrowTimer.run();
                downArrowTimer.scheduleRepeating(20);
            }

            public void onMouseEnter() {
                downArrowTimer.run();
                downArrowTimer.scheduleRepeating(20);
            }

            public void onMouseLeave() {
                downArrowTimer.cancel();
            }

            public void onMouseUp(int i, int i1) {
                downArrowTimer.cancel();
            }

            public void onMouseWheelUp(int intensity) {
                downArrowTimer.cancel();
            }

            public void onMouseWheelDown(int intensity) {

            }

            public void onMouseMove(int x, int y) {

            }
        });

    }

    public void setFixedCursorSizeAndPosition(int w, int h, int x, int y) {
        hasFixedHeight = true;
        cursor.setPixelSize(w, h);
        central.setWidgetPosition(cursor, x, y);
    }

    public void setVerticalBarWidth(int w) {
        arrowWidth = w;
        arrowHeight = w;
    }

    public int getScrollPosition() {
        return calculateDispacement();
    }

    public void resetScrollPosition() {
        central.setWidgetPosition(cursor, 0, 0);
        scrollListenerCollection.fireOnScroll(calculateDispacement());
    }

    public void setHeight(String h) {
        super.setHeight(h);
        int height = Integer.parseInt(h.replace("px", ""));
        central.setHeight((height - (2 * arrowHeight)) + "px");
        upArrow.setHeight(arrowHeight + "px");
        downArrow.setHeight(arrowHeight + "px");
    }

    public void setWidth(String w) {
        super.setWidth(arrowWidth + "px");
        int width = Integer.parseInt(w.replace("px", ""));
        central.setWidth(width + "px");
    }

    public void setUpArrowImageUrl(String url) {
        upArrow.setUrl(url, arrowWidth, arrowHeight);
        addArrowsMouseListeners();
        upArrow.setPixelSize(arrowWidth, arrowHeight);


    }

    public void setDownArrowImageUrl(String url) {
        downArrow.setUrl(url, arrowWidth, arrowHeight);
        addArrowsMouseListeners();
        downArrow.setPixelSize(arrowWidth, arrowHeight);
    }

    public int getArrowWidth() {
        return arrowWidth;
    }

    public int getArrowHeight() {
        return arrowHeight;
    }

    public void setCursorHeight(int childHeight) {
        this.childHeight = childHeight;

        double centralH = central.getOffsetHeight();
        double arrowH = arrowHeight;
        double childH = childHeight;

        double cursorHeight = ((centralH + (2 * arrowH)) / childH * (centralH));

        realCursorHeight = (int) cursorHeight;

        if (cursorHeight >= central.getOffsetHeight()) {
            return;
        }

        cursor.setPixelSize(arrowWidth, realCursorHeight);
        scrollListenerCollection.fireOnScroll(calculateDispacement());
    }

    public void addScrollListener(FScrollListener l) {
        scrollListenerCollection.add(l);
    }

    public void removeScrollListener(FScrollListener l) {
        scrollListenerCollection.remove(l);
    }

    private int calculateDispacement() {
        int maxOffset = childHeight - (central.getOffsetHeight() + (2 * arrowHeight));

        double ratio = ((double) central.getOffsetHeight()) / ((double) realCursorHeight);

        double jump = maxOffset - (((double) central.getOffsetHeight() - (double) realCursorHeight)) * ratio;

        double offset = ((double) central.getWidgetTop(cursor)) * ratio;
        offset += jump * ((double) central.getWidgetTop(cursor)) / (((double) central.getOffsetHeight() - (double) realCursorHeight));

        return (int) offset;
    }

    public void handleWheelEvent(int intensity) {
        intensity = intensity;

        if (intensity >= 0) {
            int pos = central.getWidgetTop(cursor) + central.getOffsetHeight() / 20;

            if ((pos + realCursorHeight) > (central.getOffsetHeight())) {
                central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), (central.getOffsetHeight() - realCursorHeight));
                scrollListenerCollection.fireOnScroll(calculateDispacement());
            } else {
                central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), pos);
                scrollListenerCollection.fireOnScroll(calculateDispacement());
            }
        } else {
            int pos = central.getWidgetTop(cursor) - central.getOffsetHeight() / 20;

            if (pos <= 0) {
                central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), 0);
                scrollListenerCollection.fireOnScroll(0);
            } else {
                central.setWidgetPosition(cursor, central.getWidgetLeft(cursor), pos);
                scrollListenerCollection.fireOnScroll(calculateDispacement());
            }
        }

    }

}
